package GigabitFpga

import (
	"encoding/binary"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"
)

type RecvDataHandler interface {
	// RecvData 每次收到一个完整 UDP 包就调用
	// data: 实际 IQ 数据（已切片）
	// n:    数据长度
	RecvData(data []byte, n int)
	// OnError 可选：接收错误时回调
	OnError(err error)
}

type MTCASDR_DESCRIPTOR struct {
	DeviceIP string
	LocalIP  string
	LocalMAC string

	LocalDataPort int // 默认 9080
	LocalCmdPort  int // 默认 9081

	cmdConn  *net.UDPConn // 控制通道
	dataConn *net.UDPConn // 数据通道
	cmdAddr  *net.UDPAddr // 设备控制地址 (xxx.xxx.xxx.xxx:6061)
	dataAddr *net.UDPAddr // 设备数据地址 (xxx.xxx.xxx.xxx:6060)

	seq uint8 // 控制包序号（原 nSendNum），从 1 开始递增，255 后自动回 0（硬件能接受）

	callback RecvDataHandler
	// 可选：后续如果需要支持多卡
	// ID     uint32
	// Status int32
}

// 创建硬件连接
func NewMtcasdr(deviceIP string, localIP string, localMac string, localDataPort int, localCmdPort int, hd RecvDataHandler) (*MTCASDR_DESCRIPTOR, error) {
	// ---------- 参数简单校验 ----------
	if deviceIP == "" || localIP == "" || localMac == "" {
		return nil, fmt.Errorf("deviceIP/localIP/localMac cannot be empty")
	}
	if localDataPort <= 0 || localDataPort > 65535 ||
		localCmdPort <= 0 || localCmdPort > 65535 {
		return nil, fmt.Errorf("invalid port number")
	}

	// ---------- 分配结构体 ----------
	dev := &MTCASDR_DESCRIPTOR{
		DeviceIP:      deviceIP,
		LocalIP:       localIP,
		LocalMAC:      strings.ToUpper(localMac), // MAC 通常大写
		LocalDataPort: localDataPort,
		LocalCmdPort:  localCmdPort,
		seq:           1,
		callback:      hd,
	}
	fmt.Println("[mtcasdr] device create success!")
	return dev, nil
}

func (dev *MTCASDR_DESCRIPTOR) Start() error {
	//d.initCmdSocket()      // 第一步：建控制通道
	//d.configLocalInfo()    // 第二步：发配置
	//d.sayHello()           // 第三步：验证
	//d.initDataSocket()     // 第四步：建数据通道

	if err := dev.initCmdSocket(); err != nil {
		return fmt.Errorf("init cmd socket failed: %w", err)
	}

	if err := dev.configLocalInfo(); err != nil {
		dev.Close()
		return fmt.Errorf("config local info failed: %w", err)
	}

	if err := dev.sayHello(); err != nil {
		dev.Close()
		return fmt.Errorf("say hello failed: %w", err)
	}

	if err := dev.initDataSocket(); err != nil {
		dev.Close()
		return fmt.Errorf("init data socket failed: %w", err)
	}

	if dev.callback != nil {
		if err := dev.StartRecvData(dev.callback); err != nil {
			return err
		}
	}

	fmt.Println("[mtcasdr] device connect success!")
	return nil
}

// 初始化控制通道，对应C++ mtcasdr_init_data_socket函数
func (d *MTCASDR_DESCRIPTOR) initCmdSocket() error {
	localAddr := &net.UDPAddr{IP: net.ParseIP(d.LocalIP), Port: d.LocalCmdPort}
	conn, err := net.ListenUDP("udp", localAddr)
	if err != nil {
		return err
	}
	// 设置为非阻塞模式（C 中用了 ioctlsocket FIONBIO）
	conn.SetReadBuffer(1024 * 1024)
	d.cmdConn = conn
	d.cmdAddr = &net.UDPAddr{
		IP:   net.ParseIP(d.DeviceIP),
		Port: 6061,
	}
	fmt.Println("[mtcasdr] device initCmdSocket success!")
	return nil
}

// 配置本机 MAC、IP、端口到设备（完全复刻原 C 逻辑）
func (d *MTCASDR_DESCRIPTOR) configLocalInfo() error {
	mac := d.parseMAC()

	////配置mac地址
	// 写入 MAC 低32位 → 寄存器 0x0002
	if err := d.writeReg(0x0002, uint32(mac&0xFFFFFFFF)); err != nil {
		return err
	}

	// 写入 MAC 高16位 → 寄存器 0x0003
	if err := d.writeReg(0x0003, uint32((mac>>32)&0xFFFF)); err != nil {
		return err
	}

	// 写入本机 IP → 寄存器 0x0004
	ip := net.ParseIP(d.LocalIP).To4()
	ipVal := binary.BigEndian.Uint32(ip)
	if err := d.writeReg(0x0004, ipVal); err != nil {
		return err
	}

	// 写入本地控制端口 → 0x0005
	if err := d.writeReg(0x0005, uint32(d.LocalCmdPort)); err != nil {
		return err
	}

	// 写入本地数据端口 → 0x0006
	if err := d.writeReg(0x0006, uint32(d.LocalDataPort)); err != nil {
		return err
	}

	fmt.Println("[mtcasdr] device configLocalInfo success!")
	return nil
}

// 解析 MAC 地址字符串为 uint64
func (d *MTCASDR_DESCRIPTOR) parseMAC() uint64 {
	// 支持 00:11:22:33:44:55 或 00-11-22-33-44-55
	macStr := strings.ReplaceAll(d.LocalMAC, "-", ":")
	parts := strings.Split(macStr, ":")
	fmt.Printf("parts:")
	fmt.Println(parts)
	if len(parts) != 6 {
		return 0 // 或者 panic，根据需求
	}

	var mac uint64
	for i, part := range parts {
		b, _ := strconv.ParseUint(part, 16, 8)
		mac |= b << ((5 - i) * 8)
	}
	return mac
}

// 写寄存器（op_code=0x1012）
func (d *MTCASDR_DESCRIPTOR) writeReg(addr, val uint32) error {
	// payload 对应C++ 代码中的control_pack结构体共16个字节
	payload := make([]byte, 16)
	binary.LittleEndian.PutUint16(payload[0:2], 0x1012) // op_code  操作码 写寄存器
	binary.LittleEndian.PutUint16(payload[2:4], 16)     // pack_length
	payload[4] = d.nextSeq()
	binary.LittleEndian.PutUint32(payload[8:12], addr)
	binary.LittleEndian.PutUint32(payload[12:16], val)

	_, err := d.cmdConn.WriteToUDP(payload, d.cmdAddr) //写命令不需要回应

	//_, err := d.sendCmdAndRecv(payload, 500*time.Millisecond)
	return err
}

// 发送控制命令并等待回应（超时 1 秒）
func (d *MTCASDR_DESCRIPTOR) sendCmdAndRecv(payload []byte, timeout time.Duration) ([]byte, error) {
	if _, err := d.cmdConn.WriteToUDP(payload, d.cmdAddr); err != nil {
		return nil, err
	}

	d.cmdConn.SetReadDeadline(time.Now().Add(timeout))
	buf := make([]byte, 1024)
	n, _, err := d.cmdConn.ReadFromUDP(buf)
	if err != nil {
		return nil, err
	}
	return buf[:n], nil
}

// say hello（发送心跳并验证回应）
func (d *MTCASDR_DESCRIPTOR) sayHello() error {
	for i := 0; i < 3; i++ {
		payload := make([]byte, 16)
		binary.LittleEndian.PutUint16(payload[0:2], 0x0002)
		binary.LittleEndian.PutUint16(payload[2:4], 16)
		payload[4] = d.nextSeq() // 必须加这一行！
		binary.LittleEndian.PutUint32(payload[8:12], 0x0001)

		resp, err := d.sendCmdAndRecv(payload, time.Second)
		if err != nil {
			continue
		}
		if len(resp) > 8 && resp[8] != 0 { // 设备回的第9字节（索引8）必须不为0
			fmt.Println("[mtcasdr] sayHello response success!")
			return nil // 成功
		}
	}
	//LhtLog.Logger.Info("device no response")
	return fmt.Errorf("device no response")
}

func (d *MTCASDR_DESCRIPTOR) nextSeq() uint8 {
	s := d.seq
	d.seq++
	return s
}

// 初始化数据通道
func (d *MTCASDR_DESCRIPTOR) initDataSocket() error {
	localAddr := &net.UDPAddr{IP: net.ParseIP(d.LocalIP), Port: d.LocalDataPort}
	conn, err := net.ListenUDP("udp", localAddr)
	if err != nil {
		return err
	}
	conn.SetReadBuffer(10 * 1024 * 1024) // 10MB 缓冲，千兆必备
	d.dataConn = conn
	d.dataAddr = &net.UDPAddr{
		IP:   net.ParseIP(d.DeviceIP),
		Port: 6060,
	}
	fmt.Println("[mtcasdr] device initDataSocket success!")
	return nil
}

// 关闭连接
func (d *MTCASDR_DESCRIPTOR) Close() {
	if d.cmdConn != nil {
		d.cmdConn.Close()
	}
	if d.dataConn != nil {
		d.dataConn.Close()
	}
}
